<script lang="tsx">
import useRender from "@/utils/hooks/render";
import { PickerOption } from "@nutui/nutui-taro/dist/types/__VUE/picker/types";
import { PickerView, PickerViewColumn } from "@tarojs/components";
import Taro from "@tarojs/taro";
import {
  computed,
  CSSProperties,
  PropType,
  reactive,
  ref,
  useCssModule,
  watch,
} from "vue";
// import "./index.scss";
import "@nutui/nutui-taro/dist/packages/picker/style.mjs";
import { Loading1 } from "@nutui/icons-vue-taro";
import PickerColumn from "./_part/column.h5.vue";
import { preventDefault } from "@/utils/util";
const IS_H5_ENV = process.env.TARO_ENV === "h5";

const DEFAULT_FILED_NAMES = {
  text: "text",
  value: "value",
  children: "children",
};

export default {
  name: "my-picker",
  emits: ["cancel", "change", "confirm", "update:modelValue"],
  props: {
    loading: Boolean,
    modelValue: {
      type: Array as PropType<(string | number)[]>,
      default: () => [],
    },
    columns: {
      type: Array as PropType<(PickerOption | PickerOption[])[]>,
      default: () => [],
    },
    open: Boolean,
    cancelText: {
      type: String,
      default: "取消",
    },
    okText: {
      type: String,
      default: "确定",
    },
    title: {
      type: String,
      default: "",
    },
    visibleOptionNum: {
      type: [Number, String],
      default: 7,
    },
    optionHeight: {
      type: [Number, String],
      default: 36,
    },
  },
  setup(props, ctx) {
    const style = useCssModule();

    const selectedOptionsSubmit = ref();

    const columnFieldNames = computed(() => {
      return {
        ...DEFAULT_FILED_NAMES,
        //   ...(props.fieldNames as PickerFieldNames)
      };
    });
    // 选中项
    const defaultValues = ref<(number | string)[]>([]);
    const state = reactive({
      show: false,
      picking: false,
      ENV: Taro.getEnv(),
      ENV_TYPE: Taro.ENV_TYPE,
      formattedColumns: computed(() => props.columns),
    });
    // 将传入的 columns 格式化
    const columnsList = computed(() => {
      let result: PickerOption[][] = [];
      switch (columnsType.value) {
        case "multiple":
          result = state.formattedColumns as PickerOption[][];
          break;
        case "cascade":
          // 级联数据处理
          result = formatCascade(
            state.formattedColumns as PickerOption[],
            defaultValues.value ? defaultValues.value : []
          );
          break;
        default:
          result = [state.formattedColumns] as PickerOption[][];
          break;
      }
      return result;
    });

    // 当前类型
    const columnsType = computed(() => {
      const firstColumn: PickerOption | PickerOption[] =
        state.formattedColumns[0];
      const fields = columnFieldNames.value;
      if (firstColumn) {
        if (Array.isArray(firstColumn)) {
          return "multiple";
        }
        if (fields.children in firstColumn) {
          return "cascade";
        }
      }
      return "single";
    });

    // 级联数据格式化
    const formatCascade = (
      columns: PickerOption[],
      defaultValues: (number | string)[]
    ) => {
      const formatted: PickerOption[][] = [];
      const fields = columnFieldNames.value;
      let cursor: PickerOption = {
        text: "",
        value: "",
        [fields.children]: columns,
      };

      let columnIndex = 0;

      while (cursor && cursor[fields.children]) {
        const options: PickerOption[] = cursor[fields.children];
        const value = defaultValues[columnIndex];
        let index = options.findIndex(
          (columnItem) => columnItem.value === value
        );
        if (index === -1) index = 0;
        cursor = cursor[fields.children][index];

        columnIndex++;
        formatted.push(options);
      }
      return formatted;
    };

    // 选中项的位置  taro
    const defaultIndexes = ref<number[]>([]);
    const selectedOptions = computed(() => {
      const fields = columnFieldNames.value;
      return (columnsList.value as PickerOption[][]).map(
        (column: PickerOption[], index: number) => {
          return column.find(
            (item) => item[fields.value] === defaultValues.value[index]
          );
        }
      );
    });

    const pickerViewStyles = computed(() => {
      const styles: CSSProperties = {};
      styles.height = `${+props.visibleOptionNum * +props.optionHeight}px`;
      styles["--lineHeight"] = `${+props.optionHeight}px`;
      return styles;
    });

    // 平铺展示时，滚动选择
    const tileChange = (data: any) => {
      console.log("tileChange", data);

      const prevDefaultValue = defaultIndexes.value;
      let changeIndex = 0;
      // 判断变化的是第几个
      data.detail.value.forEach((col: number, index: number) => {
        if (prevDefaultValue[index] !== col) changeIndex = index;
      });

      // 选择的是哪个 option
      changeHandler(
        changeIndex,
        columnsList.value[changeIndex][data.detail.value[changeIndex]]
      );
      // console.log('设置默认值');

      defaultIndexes.value = defaultValuesConvert();
    };

    const defaultValuesConvert = () => {
      const defaultIndexs: number[] = [];
      const fields = columnFieldNames.value;
      if (defaultValues.value.length > 0) {
        defaultValues.value.forEach((value, index) => {
          for (let i = 0; i < columnsList.value[index].length; i++) {
            if (columnsList.value[index][i][fields.value] === value) {
              defaultIndexs.push(i);
              break;
            }
          }
        });
      } else {
        if (columnsList && columnsList.value.length > 0) {
          columnsList.value.forEach((item) => {
            defaultIndexs.push(0);
            item.length > 0 && defaultValues.value.push(item[0][fields.value]);
          });
        }
      }

      return defaultIndexs;
    };

    const changeHandler = (columnIndex: number, option: PickerOption) => {
      const fields = columnFieldNames.value;
      if (option && Object.keys(option).length) {
        defaultValues.value = defaultValues.value ? defaultValues.value : [];

        if (columnsType.value === "cascade") {
          defaultValues.value[columnIndex] = option[fields.value] ?? "";
          let index = columnIndex;
          let cursor = option;
          while (
            cursor &&
            cursor[fields.children] &&
            cursor[fields.children][0]
          ) {
            defaultValues.value[index + 1] = cursor[fields.children][0].value;
            index++;
            cursor = cursor[fields.children][0];
          }

          // 当前改变列 的 下一列 children 值为空
          if (
            cursor &&
            cursor[fields.children] &&
            cursor[fields.children].length === 0
          ) {
            defaultValues.value = defaultValues.value.slice(0, index + 1);
          }
        } else {
          defaultValues.value[columnIndex] =
            Object.prototype.hasOwnProperty.call(option, fields.value)
              ? option[fields.value]
              : "";
        }

        if (!props.loading) {
          ctx.emit("change", {
            columnIndex: columnIndex,
            selectedValue: defaultValues.value,
            selectedOptions: selectedOptions.value,
          });
        }
      }
    };

    const confirm = () => {
      const fields = columnFieldNames.value;
      if (defaultValues.value && !defaultValues.value.length) {
        columnsList.value.forEach((columns) => {
          defaultValues.value.push(columns[0][fields.value]);
        });
      }

      if (!props.loading) {
        selectedOptionsSubmit.value = selectedOptions.value;
        ctx.emit("confirm", {
          selectedValue: defaultValues.value,
          selectedOptions: selectedOptions.value,
        });
      }
    };

    const isSameValue = (valA: any, valB: any) =>
      valA === valB || JSON.stringify(valA) === JSON.stringify(valB);

    // watch(
    //   defaultValues,
    //   (newValues) => {
    //     if (!isSameValue(newValues, props.modelValue)) {
    //       //   console.log("update:modelValue", newValues);

    //       /**每次拉动都会触发 */
    //       ctx.emit("update:modelValue", newValues);
    //     }
    //   },
    //   { deep: true }
    // );

    watch(
      () => props.modelValue,
      (val, oldVal) => {
        if (val?.length) {
          if (isSameValue(val, oldVal)) return;
          selectedOptionsSubmit.value = val?.map((el, idx) => {
            return columnsList.value[idx].find((item) => item.value === el);
          });
          defaultValues.value = val;
        }
      }
    );

    // 确定
    const confirmHandler = () => {
      if (props.loading) {
        return;
      }
      if (state.picking) {
        setTimeout(() => {
          confirm();
        }, 0);
      } else {
        confirm();
      }
    };

    // 开始滚动
    const handlePickstart = () => {
      state.picking = true;
    };
    // 开始滚动
    const handlePickend = () => {
      state.picking = false;
    };

    const handleClose = () => {
      ctx.emit("cancel", {
        selectedValue: defaultValues.value,
        selectedOptions: selectedOptions.value,
      });
    };

    useRender(() => (
      <view
        class="nut-picker"
        catchMove
        onTouchmove={(e) => {
          preventDefault(e as unknown as Event, true);
        }}
      >
        <nut-popup
          position="bottom"
          visible={props.open}
          onClickOverlay={handleClose}
        >
          <div class="nut-picker__bar">
            <div
              class="nut-picker__cancel nut-picker__left nut-picker__button"
              onClick={handleClose}
            >
              {props.cancelText}
            </div>
            <div class="nut-picker__title">{props.title}</div>
            <div
              class={`${
                props.loading ? style["disabled"] : ""
              } nut-picker__confirm nut-picker__right nut-picker__button`}
              onClick={confirmHandler}
            >
              {props.okText}
            </div>
          </div>

          {ctx.slots.top?.()}

          {!IS_H5_ENV ? (
            <PickerView
              indicatorStyle={`height:${props.optionHeight}px`}
              value={defaultIndexes.value}
              style={pickerViewStyles.value}
              {...ctx.attrs}
              immediateChange={true}
              onChange={tileChange}
              onPickstart={handlePickstart}
              onPickend={handlePickend}
            >
              {props.loading ? (
                <div
                  class="uno-w100% uno-flex uno-flex-justify-center uno-flex-items-center"
                  style={{ height: pickerViewStyles.value.height }}
                >
                  <Loading1 />
                </div>
              ) : (
                columnsList.value.map((el) => (
                  <PickerViewColumn>
                    {el.map((item) => (
                      <text
                        class="uno-block  uno-text-center"
                        style={{
                          height: `${props.optionHeight}px`,
                          lineHeight: `${props.optionHeight}px`,
                        }}
                      >
                        {item.text}
                      </text>
                    ))}
                  </PickerViewColumn>
                ))
              )}
            </PickerView>
          ) : (
            <view class="nut-picker__column" style={pickerViewStyles.value}>
              {columnsList.value.map((el, columnIndex) => (
                <view key={columnIndex} class="nut-picker__columnitem">
                  <PickerColumn
                    ref="swipeRef"
                    column={el}
                    columns-type={columnsType.value}
                    field-names={columnFieldNames.value}
                    value={defaultValues[columnIndex]}
                    three-dimensional={false}
                    swipe-duration={1000}
                    visible-option-num={props.visibleOptionNum}
                    option-height={props.optionHeight}
                    taro
                    onChange={(option: any) => {
                      changeHandler(columnIndex, option);
                    }}
                  ></PickerColumn>
                </view>
              ))}
            </view>
          )}

          {ctx.slots.default?.()}
        </nut-popup>
      </view>
    ));

    ctx.expose({
      selectedOptionsSubmit,
      columnsType,
    });

    return {
      defaultValues,
      state,
      columnsList,
      columnsType,
      selectedOptions,
      selectedOptionsSubmit,
    };
  },
};
</script>

<style lang="scss" module>
.disabled {
  &:global.nut-picker__right {
    color: $picker-cancel-color;
    cursor: not-allowed;
  }
}
</style>
